; Disassembly of the file "z:\ramdisk\home\knoppix\none\CPM_CHRIS_Loader.bin"
; 
; CPU Type: Z80
; 
; Created with dZ80 2.0
; 
; on Sunday, 14 of October 2012 at 06:36 PM
; 
0000 00		NOP		; first byte of CP/M loader must be $00 (!= $F3)
0001 F3		DI
0002 E5		PUSH	HL	; HL=$0000 from the BOOT ROM (end of CP/M loading routine)
0003 3EC9	LD	A,$C9	; $C9 = opcode for RET instruction of Z80
0005 320000	LD	($0000),A ; replace first byte of this loader with RET instruction
0008 CD0000	CALL	$0000	; $000B is saved on stack when this call executed ...
000B 3B		DEC	SP
000C 3B		DEC	SP
000D E1		POP	HL	; ... so now HL=$000B (nice stupid wiseass trick, big deal ...)
000E 3E41	LD	A,$41	; 
0010 D3FE	OUT	($FE),A	; write 41 to port C of 8255
;				; (set border to blue, set signal "SO" to 0, set signal "O5" to 0,
;				;  set signal "O6" to 1 to allow access to video memory in the CP/M hw config)

				; ############## DISPLAY THE "PLUS" LOGO ###############
0012 013000	LD	BC,$0030
0015 09		ADD	HL,BC	; HL=$003B
0016 11005A	LD	DE,$5A00
0019 0620	LD	B,$20
001B C5		PUSH	BC	; BC=$20xx <-- <--- <--- <--- <--- <--- <--- <--|
001C 4E		LD	C,(HL)	; C=($003B)=$00					|
001D 0608	LD	B,$08	; 8 loops next					|
001F 3E00	LD	A,$00	; <--- <--- <--- <--- <--- <--- <--- <--|	|
0021 CB01	RLC	C	; Carry Flag is 0			|	|
0023 3002	JR	NC,$0027; jump if bit=0  --->|			|	|
0025 3E12	LD	A,$12	;		     |			|	|
0027 12		LD	(DE),A	; <--- <--- <--- <---|	($5A00)=$00	|	|
0028 13		INC	DE	; DE=$5A01				|	|
0029 10F4	DJNZ	$001F	; ---> ---> ---> ---> ---> ---> ---> -->|	|
002B C1		POP	BC	; BC=$20xx					|
002C 23		INC	HL	; HL=$003C					|
002D 10EC	DJNZ	$001B	; ---> ---> ---> ---> ---> ---> ---> ---> ----->| 32 loops ($20)
002F 184A	JR	$007B

				; ############## UNUSED AREA ###################
0031 00		DEFB	$00
0032 00		DEFB	$00
0033 00		DEFB	$00
0034 00		DEFB	$00
0035 00		DEFB	$00
0036 00		DEFB	$00
0037 00		DEFB	$00
0038 00		DEFB	$00
0039 00		DEFB	$00
003a 00		DEFB	$00
				; ##############################################

				; ############## DATA START ####################
				; this block is used to generate the PLUS logo while loading CP/M
003B 00		DEFB	$00	; 5A00: 00 00 00 00 00 00 00 00		00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
003C 00		DEFB	$00	; 5A08: 00 00 00 00 00 00 00 00
003D 00		DEFB	$00	; 5A10: 00 00 00 00 00 00 00 00
003E 00		DEFB	$00	; 5A18: 00 00 00 00 00 00 00 00
003F 07		DEFB	$07	; 5A20: 00 00 00 00 00 12 12 12		00 00 00 00 00 12 12 12 00 00 00 12 00 00 00 00 00 12 00 00 12 00 00 00 12 12 00 00 00 00 00 00
0040 10		DEFB	$10	; 5A28: 00 00 00 12 00 00 00 00
0041 48		DEFB	$48	; 5A30: 00 12 00 00 12 00 00 00
0042 C0		DEFB	$C0	; 5A38: 12 12 00 00 00 00 00 00
0043 04		DEFB	$04	; 5A40: 00 00 00 00 00 12 00 00		00 00 00 00 00 12 00 00 12 00 00 12 00 00 00 00 00 12 00 00 12 00 00 12 00 00 00 00 00 00 00 00
0044 90		DEFB	$90	; 5A48: 12 00 00 12 00 00 00 00
0045 49		DEFB	$49	; 5A50: 00 12 00 00 12 00 00 12
0046 00		DEFB	$00	; 5A58: 00 00 00 00 00 00 00 00
0047 04		DEFB	$04	; 5A60: 00 00 00 00 00 12 00 00		00 00 00 00 00 12 00 00 12 00 00 12 00 00 00 00 00 12 00 00 12 00 00 12 12 12 00 00 00 00 00 00
0048 90		DEFB	$90	; 5A68: 12 00 00 12 00 00 00 00
0049 49		DEFB	$49	; 5A70: 00 12 00 00 12 00 00 12
004A C0		DEFB	$C0	; 5A78: 12 12 00 00 00 00 00 00
004B 07		DEFB	$07	; 5A80: 00 00 00 00 00 12 12 12		00 00 00 00 00 12 12 12 00 00 00 12 00 00 00 00 00 12 00 00 12 00 00 00 00 00 12 00 00 00 00 00
004C 10		DEFB	$10	; 5A88: 00 00 00 12 00 00 00 00
004D 48		DEFB	$48	; 5A90: 00 12 00 00 12 00 00 00
004E 20		DEFB	$20	; 5A98: 00 00 12 00 00 00 00 00
004F 04		DEFB	$04	; 5AA0: 00 00 00 00 00 12 00 00		00 00 00 00 00 12 00 00 00 00 00 12 00 00 00 00 00 12 00 00 12 00 00 12 00 00 12 00 00 00 00 00
0050 10		DEFB	$10	; 5AA8: 00 00 00 12 00 00 00 00
0051 49		DEFB	$49	; 5AB0: 00 12 00 00 12 00 00 12
0052 20		DEFB	$20	; 5AB8: 00 00 12 00 00 00 00 00
0053 04		DEFB	$04	; 5AC0: 00 00 00 00 00 12 00 00		00 00 00 00 00 12 00 00 00 00 00 12 12 12 12 00 00 00 12 12 00 00 00 00 12 12 00 00 00 00 00 00
0054 1E		DEFB	$1E	; 5AC8: 00 00 00 12 12 12 12 00
0055 30		DEFB	$30	; 5AD0: 00 00 12 12 00 00 00 00
0056 C0		DEFB	$C0	; 5AD8: 12 12 00 00 00 00 00 00
0057 00		DEFB	$00	; 5AE0: 00 00 00 00 00 00 00 00		00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0058 00		DEFB	$00	; 5AE8: 00 00 00 00 00 00 00 00
0059 00		DEFB	$00	; 5AF0: 00 00 00 00 00 00 00 00
005A 00		DEFB	$00	; 5AF8: 00 00 00 00 00 00 00 00
				; ############## DATA END ######################

				; ############## UNUSED AREA ###################
005b 00		DEFB	$00
005c 00		DEFB	$00
005d 00		DEFB	$00
005e 00		DEFB	$00
005f 00		DEFB	$00
0060 00		DEFB	$00
0061 00		DEFB	$00
0062 00		DEFB	$00
0063 00		DEFB	$00
0064 00		DEFB	$00
0065 00		DEFB	$00
0066 00		DEFB	$00
0067 00		DEFB	$00
0068 FF		DEFB	$FF
0069 FF		DEFB	$FF
006a 00		DEFB	$00
006b 00		DEFB	$00
006c FF		DEFB	$FF
006d FF		DEFB	$FF
006e 00		DEFB	$00
006f 00		DEFB	$00
0070 FF		DEFB	$FF
0071 FF		DEFB	$FF
0072 00		DEFB	$00
0073 00		DEFB	$00
0074 FF		DEFB	$FF
0075 FF		DEFB	$FF
0076 00		DEFB	$00
0077 00		DEFB	$00
0078 FF		DEFB	$FF
0079 FF		DEFB	$FF
007a 00		DEFB	$00
				; ##############################################

007B 3E01	LD	A,$01
007D D3FE	OUT	($FE),A	; write $01 to port C of 8255
;				; (set border to blue, set signal "SO" to 0, set signal "O5" to 0,
;				;  set signal "O6" to 0 to allow access to DRAM#1 in the hw startup config)
007F E1		POP	HL	; HL=$0000, value pushed on stack at the very beginning
0080 EB		EX	DE,HL	; DE=$0000, HL=$5B00
0081 2A9A00	LD	HL,($009A) ; HL=$0400
0084 4B		LD	C,E	; C=$00
0085 44		LD	B,H	; B=$04  --> BC=$0400
0086 EDB8	LDDR		; copy $0400-$0001 to $0000-$FC01; when done BC=$0000, DE=$FC00, HL=$0000
0088 EB		EX	DE,HL	; DE=$0000, HL=$FC00
0089 CBE5	SET	4,L	
008B CBFD	SET	7,L	; HL=$FC90
008D E9		JP	(HL)	; jump to $FC90 which is $0090 below--->|
				;					|
008E 00		NOP		;					|
008F 00		NOP		;					|
0090 1820	JR	$00B2	; <--- <---|<--- <--- <--- <--- <--- <--| <---- CTC0 Interrupt Vector (unused)
				;	   |
0092 09		DEFB	$09	;FC92	   | \ CTC1 Interrupt
0093 FD		DEFB	$FD	;FC93	   | /    Vector
0094 FC		DEFB	$FC	;FC94	   | \ CTC2 Interrupt
0095 FC		DEFB	$FC	;FC95	   | /    Vector
0096 00		DEFB	$00	;FC96	   | \ CTC3 Interrupt (not	| <-- instead, here is a time constant for CTC1: $00 means 1 interrupt for $100 bytes transferred
0097 20		DEFB	$20	;FC97	   | /    Vector      used)	| <-- instead, here is a time constant for CTC2: $20 x $100 = $2000, that is 1 interrupt for 8192 bytes = both sides of a system track
0098 FF		DEFB	$FF	;FC98	   | \ Start (top) address for saving
0099 3F		DEFB	$3F	;FC99	   | / system track #0 data - in reverse !!
009A 00		DEFB	$00	;FC9A	   | \ Here TRACK_READ will save the start (top) address ($1FFF)
009B 04		DEFB	$04	;FC9B	   | / for saving system track #1 data in reverse, after track #0 is already saved
009C 03		DEFB	$03	;FC9C	   | \ 8272 Specify command opcode
009D 03		DEFB	$03	;FC9D	   | / 3 loops for 8272_CMD (2 args required after Specify command opcode)
009E 08		DEFB	$08	;FC9E	   | \ 8272 Sense Interrupt Status command opcode
009F 01		DEFB	$01	;FC9F	   | / 1 loop for 8272_CMD (no args required for SIS cmd)
00A0 04		DEFB	$04	;FCA0	   | \ 8272 Sense Drive Status command opcode
00A1 02		DEFB	$02	;FCA1	   | / 2 loops for 8272_CMD (1 arg required after Sense Drive Status command opcode)
00A2 0F		DEFB	$0F	;FCA2	   | \ 8272 Seek command opcode
00A3 03		DEFB	$03	;FCA3	   | / 3 loops for 8272_CMD (2 args required after Seek command opcode)
00A4 4A		DEFB	$4A	;FCA4	   | \ 8272 Read ID command opcode with MFM
00A5 02		DEFB	$02	;FCA5	   | / 2 loops for 8272_CMD (1 arg required after opcode)
00A6 C6		DEFB	$C6	;	   | \ 8272 Read Data command opcode with MFM and MT(MultiTrack)
00A7 09		DEFB	$09	;	   | / 9 loops for 8272_CMD (8 args required after Read Data command opcode)
00A8 EF		DEFB	$EF	;FCA8	   | arg #1 for 8272 Specify cmd: SRT+HUT (Step Rate Time = 2 ms, Head Unload Time = 240 ms)
00A9 3F		DEFB	$3F	;FCA9  *** | arg #2 for 8272 Specify cmd: HLT+ND (Head Load Time = 126 ms, Non-DMA = 1)			*** This is different from LK.SYS
00AA 00		DEFB	$00	;FCAA	   | arg #1 for 8272 Seek cmd: (HDS+DS1+DS0) HDS kept on 0 while DS1+DS2 incremented
00AB 00		DEFB	$00	;FCAB	   | C = cylinder number
00AC 00		DEFB	$00	;FCAC	   | H = head number
00AD 00		DEFB	$00	;FCAD	   | R = sector number
00AE 00		DEFB	$00	;FCAE	   | N = bytes/sector
00AF 00		DEFB	$00	;	   |
00B0 FF		DEFB	$FF	;	   |
00B1 FF		DEFB	$FF	;	   |
				;	   |
00B2 F3		DI		; <--- <---| LATER USED FOR 8272 CMD RESULT STORAGE - $FCB2-$FCB8   <---   this is at $FCB2 when executed
00B3 F9		LD	SP,HL	; HL=$FC90, set stack at $FC90			      $FCB2-$FCB8
00B4 ED5E	IM	2	; interrupt mode 2				      $FCB2-$FCB8
00B6 7C		LD	A,H	; A=$FC						      $FCB2-$FCB8
00B7 ED47	LD	I,A	; I=$FC = upper half of CTC interrupt vector address  $FCB2-$FCB8

00B9 7D		LD	A,L	; A=$90 = lower half of CTC interrupt vector address ...
00BA D3E3	OUT	($E3),A	; ... is sent to CTC channel 0 (bit 0 = 0 means Vector)
				; MEANING: Interrupt Vector being used by all 4 channels!!
				; Interrupt Vector = 10010cc0 where cc is the CTC channel requesting the interrupt.
				; So vector for CTC0 = $90, CTC1 = $92, CTC2 = $94, CTC3 = $96
				; The upper half of addr table pointer is $FC which is $00 within this CP/M loader (after relocation, $0000 is at $FC00).
00BC 3EFF	LD	A,$FF	; Control word for CTC0 on next line (Enable Interrupt, Counter Mode, Rising Edge, Time Const. Follows, Reset, Control).
				; MEANING: Reset, Enable Interrupts for Channel 0, a Time Constant follows.
00BE D3E3	OUT	($E3),A	; Write control word $FF to CTC channel 0 
00C0 3E01	LD	A,$01	; Time constant for CTC0 on next line:
				; MEANING: CTC0 generates INT for each byte transferred from 8272 to µP
00C2 D3E3	OUT	($E3),A	; Write time constant $01 to CTC channel 0
00C4 3E7B	LD	A,$7B	; Control word for CTC Channel 3 on next line (Disable Interrupt, Counter Mode, Rising Edge, No Time Constant Follows, Reset, Control)
				; MEANING: Reset, Disable Interrupts for Channel 3
00C6 D3FB	OUT	($FB),A	; Send control word to CTC Channel 3

00C8 2A92FC	LD	HL,($FC92) ; HL=$FD09 = interrupt vector for the routine call below (address of CTC1 Interrupt Service Routine)
00CB CD0CFD	CALL	$FD0C	; Call CTC1+2_INIT (deactivates CTC0 int. routine)
00CE CD4FFD	CALL	$FD4F	; Call 8272_READ to read command result bytes from 8272 Data Register (to make sure there's no unfinished command)
00D1 21A8FC	LD	HL,$FCA8 ; addr for the 2 Specify command args
00D4 ED4B9CFC	LD	BC,($FC9C) ; B=$03 (2 args after 8272 cmd opcode), C=$03 (8272 Specify command opcode)
00D8 CD2FFD	CALL	$FD2F	; Call 8272_CMD_HL to send Specify command to 8272
00DB D9		EXX	; #------------------------------# <--- <--- <--- <--- <--- <--- <--- <--- <--- <--- <--- <--- <---|
00DC ED4BA0FC	LD	BC,($FCA0) ; B=$02 (1 arg after 8272 cmd opcode), C=$04 (8272 Sense Drive Status command opcode)   |
00E0 CD2CFD	CALL	$FD2C	; Call 8272_CMD to send Sense Drive Status command to 8272				   |
00E3 CD4FFD	CALL	$FD4F	; Call 8272_READ to read command result bytes from 8272 Data Register			   |
00E6 CB6F	BIT	5,A	; test bit 5 of ST3 (status of RDY signal from FDD,should be 1(?) if READY)		   |
00E8 D9		EXX	; #------------------------------#								   |
00E9 2005	JR	NZ,$00F0 ; jump if FDD Ready --> -->|								   |
00EB 34		INC	(HL)	; HL=$FCA8+2=$FCAA after the call to 8272_CMD_HL 8 lines above, ($FCAA)=00 initially=arg #1 for 8272 Seek cmd	** increment drive number **
00EC CB96	RES	2,(HL)	; make sure HDS=0 for 8272 Seek cmd							   |
00EE 18EB	JR	$00DB	; ---> ---> ---> ---> ---> ---> ---> ---> ---> ---> ---> ---> ---> ---> ---> ---> ---> --->|
00F0 CD71FD	CALL	$FD71	; <--- <--- <--- <--- <-----| call TRACK_READ, reads track 00 both sides
00F3 CD71FD	CALL	$FD71	;			      call TRACK_READ, reads track 01 both sides
00F6 E9		JP	(HL)

				; ################ CTC0 Interrupt Service Routine (this reads floppy data bytes) ########
00F7 EDA2	INI		; ----------------------- FCF7 after relocation -------------------------
00F9 FB		EI
00FA ED4D	RETI

				; ################ CTC2 Interrupt Service Routine #######################
00FC E5		PUSH	HL	; ----------------------- FCFC after relocation -------------------------
00FD 2A92FC	LD	HL,($FC92) ; HL=$FD09
0100 2290FC	LD	($FC90),HL ; ($FC90) = CTC0 Interrupt Service Routine addr = $FD09 = CTC1 Interrupt Service Routine (does nothing) *** this deactivates CTC0 routine ***
0103 21F0FC	LD	HL,$FCF0
0106 36FF	LD	(HL),$FF ; ($FCF0)=$FF		mystery byte	%%%%%%%%%%%%% ??????????????? MODIFY CODE ???????????????? %%%%%%%%%%%%%%
0108 E1		POP	HL
				; ################ CTC1 Interrupt Service Routine (does nothing) ########
0109 FB		EI		; ----------------------- FD09 after relocation -------------------------
010A ED4D	RETI

				; ############################ CTC1+2_INIT ##############################
010C F3		DI		; ----------------------- FD0C after relocation -------------------------
010D 2290FC	LD	($FC90),HL ; set CTC0 interrupt vector to value in HL ($FD09 = CTC1 Interrupt Service Routine, does nothing) *** this deactivates CTC0 routine ***
0110 3E7F	LD	A,$7F	; Control word for CTC1 below (Disable Interrupt, Counter Mode, Rising Edge, Time Constant Follows, Reset, Control)
				; MEANING: Reset, Disable Interrupts for Channel 1
0112 D3EB	OUT	($EB),A	; Send control word to CTC channel 1
0114 3A96FC	LD	A,($FC96) ; A=$00 = time constant for CTC1 below
				; MEANING: Channel 1 counts every 256 bytes transferred
0117 D3EB	OUT	($EB),A ; Send time constant to CTC channel 1
0119 3EFF	LD	A,$FF	; Control word for CTC2 below (Enable Interrupt, Counter Mode, Rising Edge, Time Constant Follows, Reset, Control)
				; MEANING: Reset, Enable Interrupts for Channel 2
011B D3F3	OUT	($F3),A ; Send control word to CTC channel 2
011D 3A97FC	LD	A,($FC97) ; A=$20 = time constant for CTC2 below
				; MEANING: Channel 2 counts every $20 x $100 = $2000 = 8192 bytes transferred from 8272 (both sides of a system track, each having 1 sector with 4096 bytes)
0120 D3F3	OUT	($F3),A ; Send time constant to CTC channel 2
0122 C9		RET

				; ############################ 8272_POLL ################################
				; ----------------------- FD23 after relocation -------------------------
0123 DBF5	IN	A,($F5)	; read 8272 Status Register <--- <--- <--- <--- <--- <-----|		| this routine polls the 8272 Status Register
0125 CB7F	BIT	7,A	; test bit 7 (RQM) to see if 8272 ready to send or receive |		| until 8272 is ready to send or receive
0127 28FA	JR	Z,$0123	; jump if 8272 not ready ---> ---> ---> ---> ---> ---> --->|		| data to or from the CPU. When ready (RQM=1)
0129 CB77	BIT	6,A	; test bit 6 (DIO) to determine direction of data transfer		| bit 6 is tested (DIO, 0=send/1=receive)
012B C9		RET

				; ############################ 8272_CMD ##################################
				; ----------------------- FD2C after relocation -------------------------
				; BC = parameter to this subroutine: B = loop count for DJNZ $0137, C = command opcode to write to 8272 Data Register
012C 21AAFC	LD	HL,$FCAA ; address of 8272 command parameter bytes following the command opcode
				; ############################ 8272_CMD_HL ###############################
				; ----------------------- FD2F after relocation -------------------------
				; this entry point requires HL = additional parameter as address of 8272 command parameter bytes following the command opcode
012F DBF5	IN	A,($F5)	; read 8272 Status Register <----|
0131 CB67	BIT	4,A	; test bit 4 (FDC Busy)		 |
0133 20FA	JR	NZ,$012F; if FDC Busy jump ---> ---> --->|
0135 1802	JR	$0139	; ---> ---> --->|
0137 4E		LD	C,(HL)	; <---- <--- <--- <--- <--- <---| C = (next) 8272 cmd parameter byte
0138 23		INC	HL	;		|		| increment 8272 cmd parameter pointer
0139 F3		DI		; <--- <--- <---|		|
013A CD23FD	CALL	$FD23	; Call 8272_POLL		|
013D 2022	JR	NZ,$0161; jump to CPM_TO_COBRA if transfer is TO CPU
013F 59		LD	E,C	; E=8272 cmd byte		|  <<< this will leave E'=$02 when 8272_CMD is called from TRACK_READ at $0197 within this binary file
0140 0EFD	LD	C,$FD	; 8272 Data Register port addr	|	since the second command byte of Read ID will be $02 (CP/M boots from drive 2, head 0)
0142 ED59	OUT	(C),E	; write to 8272 Data Register	|		(for later when CP/M starts with BIOS function 00 BOOT !!!!)
0144 10F1	DJNZ	$0137	; ----> ---> ---> ---> ---> --->|  <<< this will leave C'=$02 when 8272_CMD is called from TRACK_READ at $0197 within this binary file
0146 FB		EI		;					since the second command byte of Read ID will be $02 (CP/M boots from drive 2, head 0)
0147 C9		RET	;							(for later when CP/M starts with BIOS function 00 BOOT !!!!)
				; ############################ 8272_CMD_SIS ##############################
				; ----------------------- FD48 after relocation -------------------------
0148 ED4B9EFC	LD	BC,($FC9E) ; C=08=Sense Interrupt Status opcode, B=01=0 args req'd
014C CD2FFD	CALL	$FD2F	; Call 8272_CMD_HL to send Sense Interrupt Status cmd

				; ############################ 8272_READ #################################
				; ----------------------- FD4F after relocation -------------------------
				; Read command result bytes from 8272 Data Register and store them at FCB2-FCB8.
				; Normally max. 7 command result bytes can be read and normal exit is by jump at 0157
				; If after 7 bytes read the transfer direction detected does not change to "CPU -> 8272"
				; then something is wrong and a jump is made to BOOT hw config (JR Z,$016C)
014F 21B2FC	LD	HL,$FCB2
0152 0608	LD	B,$08	; 8 loops next
0154 CD23FD	CALL	$FD23	; Call 8272_POLL<--- <--- <--- <--- <---|
0157 2813	JR	Z,$016C	; Jump if transfer is FROM CPU -----> ---> ---> --->|
0159 36FF	LD	(HL),$FF ; ($FCB2+nn)=FF			|	    |
015B DBFD	IN	A,($FD)	; read 1 byte from 8272 Data Register	|	    |
015D 77		LD	(HL),A	; store byte at ($FCB2+nn)		|	    |
015E 23		INC	HL	;					|	    |
015F 10F3	DJNZ	$0154	; ---> ---> ---> ---> ---> ---> ---> -->|	    |  <<< this should leave B'=$01 for later when CP/M starts with BIOS function 00 BOOT !!!!
0161 F3		DI		; ############## CPM_TO_COBRA ##############	    |		 (7 result bytes are read after Read ID command)
0162 AF		XOR	A	; A=00						    |
0163 6F		LD	L,A	;						    |
0164 67		LD	H,A	; HL=0000					    |
0165 F6C1	OR	$C1	; A=$C1						    |
0167 D3FE	OUT	($FE),A	; write $C1 to port C of 8255			    |
;				; (set border to blue, set signal "SO" to 1, set signal "O5" to 0,
;				;  set signal "O6" to 1 to allow access to video memory in the hw startup config)
0169 ED4F	LD	R,A	; set bit 7 of R to 1 to prepare jump to startup (COBRA BOOT) hw config
016B E9		JP	(HL)	; jump to (HL)=$0000				    |
				;						    |
016C 21B2FC	LD	HL,$FCB2 ; <--- <--- <--- <--- <--- <--- <--- <--- <--- <---|  <<< this leaves HL'=$FCB2 for later when CP/M starts with BIOS function 00 BOOT !!!!
016F 7E		LD	A,(HL)	; Load first command result byte in A
0170 C9		RET

				; ############################ TRACK_READ ################################
				; ----------------------- FD71 after relocation -------------------------
0171 ED4BA2FC	LD	BC,($FCA2) ; B=$03 (2 args after 8272 cmd opcode), C=$0F (8272 Seek command opcode)
0175 CD2CFD	CALL	$FD2C	; Call 8272_CMD to send Seek command to 8272
0178 CD48FD	CALL	$FD48	; Call 8272_CMD_SIS <--- <--- <--- <--- <--- <--- <-|
017B CB6F	BIT	5,A	; Test bit 5 of result ST0, SE byte = Seek End	    |
017D 28F9	JR	Z,$0178	; Jump if Seek not finished ---> ---> ---> ---> --->|
017F E650	AND	$50	; 
0181 20DE	JR	NZ,$0161 ; Jump to CPM_TO_COBRA if HD or US0 are 1
0183 CD48FD	CALL	$FD48	; Call 8272_CMD_SIS <--- <--- <---|
0186 FE80	CP	$80	; Check if Invalid Command issue  | (check if SIS ended abnormally)
0188 20F9	JR	NZ,$0183 ; jump if not ---> ---> ---> --->|
				; *** the above loop goes until SIS becomes Invalid Command because it does not immediately follow a Seek or Recalibrate command
				; *** it is used as No-Op command, to place the FDC in a standby or no operation state.
018A DBF5	IN	A,($F5)	; read 8272 Status Register <--- <--- <--- <-----|
018C E60F	AND	$0F	; Check if any FDD is in Seek Mode (Main Status Register bits 0-3)
018E 20FA	JR	NZ,$018A ; jump if any FDD is in Seek Mode ---> ---> --->|
0190 0603	LD	B,$03	; loop counter - next loop goes 3 times
0192 D9		EXX		; <---- <--- <--- <--- <--- <---|
0193 ED4BA4FC	LD	BC,($FCA4) ; B=$02 (1 arg after 8272 cmd opcode), C=$4A (8272 Read ID command opcode with MFM)
0197 CD2CFD	CALL	$FD2C	; Call 8272_CMD to send Read ID command to 8272
019A CD4FFD	CALL	$FD4F	; Call 8272_READ and save	| Read ID result bytes at $FCB2-$FCB8
019D E6C0	AND	$C0	; Check for Abnormal Termination (bits 6-7 of ST0)
019F D9		EXX		;				|
01A0 2804	JR	Z,$01A6 ; jump if normal termination ------> --->|
01A2 10EE	DJNZ	$0192	; ----> ---> ---> ---> ---> --->| 3 attempts to read a proper ID Address Mark from disk
01A4 18BB	JR	$0161	; Jump to CPM_TO_COBRA			 |
01A6 21B5FC	LD	HL,$FCB5 ; <---- <---- <---- <---- <---- <---- <-|
01A9 11ABFC	LD	DE,$FCAB
01AC 010400	LD	BC,$0004
01AF EDB0	LDIR		; copy the last 4 Read ID result bytes from $FCB2-$FCB8 to $FCAB-$FCAE (C, H, R, N)    *** when done, HL=$FCB9, DE=$FCAF ***
01B1 2B		DEC	HL	; HL=$FCB8
01B2 46		LD	B,(HL)	; B = 4th Read ID result byte: N (bytes/sector) which is 4096 for this stupidly "protected" system
01B3 2B		DEC	HL	; HL=$FCB7
01B4 7E		LD	A,(HL)	; A = 3rd Read ID result byte: R (sector number)
01B5 12		LD	(DE),A	; ($FCAF)=sector number
01B6 C5		PUSH	BC	; *** SAVE BC ***   <---- <---- <---- <---- <---- <---- <---- <----| this loop goes N=4096 times or until no error occured while reading
01B7 AF		XOR	A	; A=00								   |
01B8 32F0FC	LD	($FCF0),A ; ($FCF0)=$00		mystery byte	%%%%%%%%%%%%% ??????????????? MODIFY CODE ???????????????? %%%%%%%%%%%%%%
01BB 21F7FC	LD	HL,$FCF7 ; value for set CTC0 interrupt vector to, when CTC1+2_INIT is called next
01BE CD0CFD	CALL	$FD0C	; Call CTC1+2_INIT - sets CTC0 interrupt vector to $FCF7	   |
01C1 23		INC	HL	; HL=$FCF8, ($FCF8)=$A2=part of the opcode for the INI instruction |
01C2 CBDE	SET	3,(HL)	; now ($FCF8)=$AA, so at $FCF7 now we have the opcode $EDAA which is the Z80 instruction IND (instead of INI) - stupid smartass way to hide the fact that system sectors are written in reverse on disk !!!
01C4 ED4BA6FC	LD	BC,($FCA6) ; B=$09, C=$C6 (8272 Read Data command opcode with MFM and MT(MultiTrack))
01C8 CD2CFD	CALL	$FD2C	; Call 8272_CMD to send Read Data command to 8272		   |
01CB 2A98FC	LD	HL,($FC98) ; HL=$3FFF = top address for saving system tracks data (sectors read normally but saving to mem will be done downwards, to $0000)
01CE 76		HALT		; <---- <---- <---- <---- <---- <-----| during this loop both sides of one system track (2 sectors x 4096 bytes each) are read from disk and saved to mem
01CF DBF5	IN	A,($F5)	; read 8272 Status Register	      |				   |
01D1 E620	AND	$20	; test bit 5 (0 means non-DMA execution phase has ended)	   |
01D3 20F9	JR      NZ,$01CE ; jump if not ended ----> ----> ---->|				   |
01D5 229AFC	LD	($FC9A),HL ; save the current sector data saving address for next system track, to ($FC9A-$FC9B)
01D8 2A92FC	LD	HL,($FC92) ; HL=FD09 = interrupt vector for the routine call below (address of CTC1 Interrupt Service Routine)
01DB CD0CFD	CALL	$FD0C	; Call CTC1+2_INIT - sets CTC0 interrupt vector to $FD09 (disables CTC0 Interrupt Service Routine)
01DE CD4FFD	CALL	$FD4F	; Call 8272_READ and save result bytes at FCB2-FCB8		   |
01E1 3AF0FC	LD	A,($FCF0) ; mystery byte						   |
01E4 B7		OR	A	; test if mystery byte = 00					   |
01E5 C1		POP	BC	; *** RESTORE BC ***						   |
01E6 2805	JR	Z,$01ED ; ----> ----> ----> ----> ----> ----> ---->|			   |
01E8 7E		LD	A,(HL)	; A=(FCB2) first Read Data result byte     | which is ST0	   |
01E9 E6D8	AND	$D8	; check error bits in ST0		   |			   |
01EB 2805	JR	Z,$01F2	; jump if no error--> ---->|		   |			   |
01ED 10C7	DJNZ	$01B6	; ----> ----> ----> ----> ----> ----> ---->+----> ----> ----> ---->|
01EF C361FD	JP	$FD61	; jump to CPM_TO_COBRA	   | (if reading errors occured)
01F2 21ABFC	LD	HL,$FCAB ; <----- <---- <---- <----| ($FCAB)=cylinder number (C, 4th Read ID result byte)
01F5 34		INC	(HL)	; increment cylinder number
01F6 2A9AFC	LD	HL,($FC9A) ; HL = the current saving address
01F9 2298FC	LD	($FC98),HL ; Overwrite the initial (top) saving address with the current one
01FC 23		INC	HL	; When this routine is called the second time to read the second system track,
				; at this point the current saving address in HL will be $0000 - 1 = $FFFF.
				; So INC HL will bring it to $0000 since after the second call of this procedure
				; a JP (HL) is executed (see the end of main code) to jumpstart the CP/M system.
01FD C9		RET

01FE 00		DEFB	$00
01FF 00		DEFB	$00